use diesel::{Queryable,Insertable};
use chrono::prelude::*;
use super::schema::*;
use serde::{Serialize, Deserialize};

#[derive(Serialize, Debug, Queryable, PartialEq)]
pub struct User {
    pub id: String,
    pub username: String,
    pub password: String,
    pub avatar: Option<String>,
    pub enable: Option<bool>,
    pub created_at: Option<NaiveDateTime>,
    pub updated_at: Option<NaiveDateTime>,
}


#[derive(Deserialize, Debug, Insertable)]
#[table_name = "users"]
pub  struct NewUser {
    pub id: String,
    pub username: String,
    pub password: String,
    pub avatar: Option<String>,
    pub enable: Option<bool>,
}

#[derive(Serialize, Clone, Debug, Queryable, PartialEq)]
pub struct Type {
    pub id: String,
    pub pid: Option<String>,
    pub name: String,
    pub rank: Option<i32>,
    pub description: Option<String>,
    pub keyword: Option<String>,
    pub icon:Option<String>,
    pub pic:Option<String>,
    pub has_tutorial: Option<bool>,
    pub hidden: Option<bool>,
    pub created_at: Option<NaiveDateTime>,
}

#[derive(Deserialize, Debug, Insertable)]
#[table_name = "types"]
pub struct NewType {
    pub id: String,
    pub pid: Option<String>,
    pub name: String,
    pub rank: Option<i32>,
    pub description: Option<String>,
    pub keyword: Option<String>,
    pub icon:Option<String>,
    pub pic:Option<String>,
    pub has_tutorial: Option<bool>,
    pub hidden: Option<bool>,
}


#[derive(Serialize, Clone, Debug, Queryable, PartialEq)]
pub struct Tutorial {
    pub id: String,
    pub pid: Option<String>,
    pub tid: String,
    pub title: String,
    pub rank: Option<i32>,
    pub description: Option<String>,
    pub keyword: Option<String>,
    pub content:String,
    pub hidden: Option<bool>,
    pub created_at: Option<NaiveDateTime>,
    pub updated_at: Option<NaiveDateTime>,
}



#[derive(Deserialize, Debug, Insertable)]
#[table_name = "tutorials"]
pub struct NewTutorial {
    pub id: String,
    pub pid: Option<String>,
    pub tid: String,
    pub title: String,
    pub rank: Option<i32>,
    pub description: Option<String>,
    pub keyword: Option<String>,
    pub content:String,
    pub hidden: Option<bool>,
}



impl Node for Type{
    fn id(&self)->String {
        self.id.clone()
    }

    fn pid(&self)->Option<String> {
        self.pid.clone()
    }
}


impl Node for Tutorial{
    fn id(&self)->String {
        self.id.clone()
    }

    fn pid(&self)->Option<String> {
        self.pid.clone()
    }
}

// 用于生成2层树状结构
#[derive(Debug, Serialize)]
pub struct TreeNode<T> {
    pub node: T,
    pub children: Vec<TreeNode<T>>,
}

pub trait Node{
    fn id(&self)->String;
    fn pid(&self)->Option<String>;
}

impl<T> TreeNode<T> where T: Node + Clone {
    pub fn new(list: Vec<T>) -> Vec<TreeNode<T>> {
        let mut nodes = vec![];

        for t in &list {
            if let Some(s) = t.pid() {
                if s == "" {
                    let mut node = TreeNode {
                        node: t.clone(),
                        children: vec![],
                    };
                    for t1 in &list {
                        if let Some(s) = t1.pid() {
                            if *s == t.id() {
                                node.children.push(TreeNode {
                                    node: t1.clone(),
                                    children: vec![],
                                });
                            }
                        }
                    }
                    nodes.push(node);
                }
            }
        }
        nodes
    }
}
